#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN PA0
#define SS_PIN PA1

MFRC522 mfrc522(SS_PIN, RST_PIN);

#include <DFRobotDFPlayerMini.h>  // 包含DFPlayerMini库

DFRobotDFPlayerMini myDFPlayer;  // 创建DFPlayer对象

// 扩展的已知密钥列表
const byte NR_KNOWN_KEYS = 8;
byte knownKeys[NR_KNOWN_KEYS][MFRC522::MF_KEY_SIZE] = {
  { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 },  // 成功密钥
  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },  // 默认密钥
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },  // 空密钥
  { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 },  // 交通卡密钥
  { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF },
  { 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6 },
  { 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5 },
  { 0x4D, 0x3A, 0x99, 0xC3, 0x51, 0xDD }  // 门禁常用
};

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);  // 启动软件串口与DFPlayer Mini通信

  // 初始化DFPlayer Mini
  if (!myDFPlayer.begin(Serial2)) {
    Serial.println(F("无法与DFPlayer Mini通信:"));
    Serial.println(F("1. 请检查连接!"));
    Serial.println(F("2. 请插入SD卡!"));
    while (true)
      ;  // 卡死在这里
  }

  myDFPlayer.volume(15);// 设置音量(0-30)
  Serial.println(F("DFPlayer Mini 在线!"));

  SPI.begin();
  mfrc522.PCD_Init();
  Serial.println(F("RFID 读取器就绪 - 支持 Classic 和 Ultralight"));
  Serial.println(F("将从块 4 读取到块 0xFE，支持中文显示"));
}

void loop() {
  if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial())
    return;

  // 显示卡片信息
  Serial.print(F("\n卡片 UID:"));
  dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();
  Serial.print(F("卡片类型: "));
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  String cardData = "";
  if (piccType == MFRC522::PICC_TYPE_MIFARE_MINI || piccType == MFRC522::PICC_TYPE_MIFARE_1K || piccType == MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("检测到 MIFARE Classic 卡片"));
    delay(300);
    cardData = readClassicCard();
    Serial.println(cardData);
  } else if (piccType == MFRC522::PICC_TYPE_MIFARE_UL) {
    Serial.println(F("检测到 MIFARE Ultralight 卡片"));
    delay(300);
    cardData = readUltralightCard();
  } else {
    Serial.println(F("不支持的卡片类型"));
  }
  Serial.println(F("\n读取完成!"));
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();

  Serial.println(cardData);
  processCardData(cardData);
                                    
  delay(2000);
}

// 静态变量用于跨页保存不完整的UTF-8字节
static byte pending[3];
static byte pendingCount = 0;

// 读取MIFARE Classic卡片
String readClassicCard() {
  //清空 pending 数组
  memset(pending, 0, sizeof(pending));
  pendingCount = 0;  // 每次读取新卡时重置

  byte maxSector;
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);

  if (piccType == MFRC522::PICC_TYPE_MIFARE_4K) {
    maxSector = 40;
    Serial.println(F("-> MIFARE Classic 4K (40 扇区)"));
  } else if (piccType == MFRC522::PICC_TYPE_MIFARE_1K) {
    maxSector = 16;
    Serial.println(F("-> MIFARE Classic 1K (16 扇区)"));
  } else if (piccType == MFRC522::PICC_TYPE_MIFARE_MINI) {
    maxSector = 5;
    Serial.println(F("-> MIFARE Mini (5 扇区)"));
  } else {
    Serial.println(F("-> 未知类型"));
  }

  Serial.println(F("开始从块 4 读取，遇到 0xFE 停止..."));

  bool foundFE = false;
  String parsedData = "";  // 存储解析后的字符串

  for (byte sector = 0; sector < maxSector && !foundFE; sector++) {
    byte firstBlock, blockSize;
    if (sector < 32) {
      firstBlock = sector * 4;
      blockSize = 4;
    } else {
      firstBlock = 32 * 4 + (sector - 32) * 16;
      blockSize = 16;
    }

    byte trailerBlock = firstBlock + blockSize - 1;

    // 跳过完全在块 4 之前的扇区
    if (firstBlock + blockSize <= 4) continue;
    if (firstBlock > 0xFE) break;

    // 认证扇区
    bool authSuccess = false;
    MFRC522::MIFARE_Key key;

    for (byte k = 0; k < NR_KNOWN_KEYS; k++) {
      for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = knownKeys[k][i];
      }

      MFRC522::StatusCode authStatus = mfrc522.PCD_Authenticate(
        MFRC522::PICC_CMD_MF_AUTH_KEY_A,
        trailerBlock,
        &key,
        &(mfrc522.uid));

      if (authStatus == MFRC522::STATUS_OK) {
        authSuccess = true;
        break;
      }

      if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
        Serial.println(F("卡片已移开"));
        break;
      }
    }

    if (!authSuccess) {
      Serial.print(F("扇区 "));
      Serial.print(sector);
      Serial.println(F(" 认证失败"));
      break;
    }

    // 遍历该扇区的数据块（跳过尾块）
    for (byte block = 0; block < blockSize - 1 && !foundFE; block++) {
      byte blockAddr = firstBlock + block;

      // 只处理块号 >= 4
      if (blockAddr < 4) continue;

      Serial.print(F("块 "));
      Serial.print(blockAddr, DEC);
      Serial.print(F(" (0x"));
      Serial.print(blockAddr, HEX);
      Serial.print(F("): "));

      byte buffer[18];
      byte size = sizeof(buffer);
      MFRC522::StatusCode status = mfrc522.MIFARE_Read(blockAddr, buffer, &size);

      if (status == MFRC522::STATUS_OK) {
        dump_byte_array(buffer, 16);

        // === 检查当前块是否有 0xFE ===
        byte validLen = 16;
        bool hasFE = false;
        for (byte i = 0; i < 16; i++) {
          if (buffer[i] == 0xFE) {
            validLen = i;  // 只处理 0xFE 前的数据
            hasFE = true;
            foundFE = true;
            break;
          }
        }

        // === 创建完整缓冲区 (pending + 当前块有效数据) ===
        byte fullBuffer[19];  // pending(最大3) + 当前块(最大16)
        byte fullLen = 0;

        // 复制 pending
        for (byte i = 0; i < pendingCount; i++) {
          fullBuffer[fullLen++] = pending[i];
        }
        // 复制当前块有效字节
        for (byte i = 0; i < validLen; i++) {
          fullBuffer[fullLen++] = buffer[i];
        }

        // === 解析并输出字符 ===
        Serial.print("  |  ");
        byte pos = 0;
        while (pos < fullLen) {
          byte c = fullBuffer[pos];

          // 处理空字节或 0xFE
          if (c == 0x00 || c == 0xFE) {
            parsedData += (c == 0x00) ? '.' : '*';
            Serial.print((c == 0x00) ? '.' : '*');
            pos++;
            continue;
          }

          // ASCII 可打印字符
          if (c >= 0x20 && c <= 0x7E) {
            parsedData += (char)c;
            Serial.write((char)c);
            pos++;
            continue;
          }

          // 处理 UTF-8 字符（2 字节或 3 字节）
          if ((c & 0xE0) == 0xC0) {         // 2 字节 UTF-8
            if (pos + 1 >= fullLen) break;  // 字节不足
            parsedData += (char)c;
            parsedData += (char)fullBuffer[pos + 1];
            Serial.write(c);
            Serial.write(fullBuffer[pos + 1]);
            pos += 2;
          } else if ((c & 0xF0) == 0xE0) {  // 3 字节 UTF-8
            if (pos + 2 >= fullLen) break;  // 字节不足
            // 检查后续字节有效性
            if ((fullBuffer[pos + 1] & 0xC0) == 0x80 && (fullBuffer[pos + 2] & 0xC0) == 0x80) {
              parsedData += (char)c;
              parsedData += (char)fullBuffer[pos + 1];
              parsedData += (char)fullBuffer[pos + 2];
              Serial.write(c);
              Serial.write(fullBuffer[pos + 1]);
              Serial.write(fullBuffer[pos + 2]);
              pos += 3;
            } else {
              parsedData += '.';
              Serial.print('.');
              pos++;
            }
          } else {
            parsedData += '.';
            Serial.print('.');
            pos++;
          }
        }

        // === 更新 pending ===
        pendingCount = 0;
        if (!hasFE) {
          pendingCount = fullLen - pos;
          for (byte i = 0; i < pendingCount; i++) {
            pending[i] = fullBuffer[pos + i];
          }
        }

        // === 处理 0xFE 标志 ===
        if (hasFE) {
          Serial.print("  <<< 找到 0xFE，停止读取!");
        }
        Serial.println();

      } else {
        Serial.print(F("读取失败 ["));
        Serial.print(mfrc522.GetStatusCodeName(status));
        Serial.println("]");
        break;
      }

      if (foundFE) break;  // 已找到 0xFE，停止读取
    }
  }

  if (foundFE) {
    Serial.println(F("✅ 已检测到 0xFE，停止读取。"));
  } else {
    Serial.println(F("⚠️ 未在块 4 起始的数据中找到 0xFE。"));
  }

  return extractFromEn(parsedData);  // 返回解析后的字符串
}

// 读取 MIFARE Ultralight 卡片：从页 4 开始，遇到 0xFE 停止
static byte pageTotal = 135;
String readUltralightCard() {
  Serial.println(F("开始从页 4 读取，遇到 0xFE 停止..."));

  //清空 pending 数组
  memset(pending, 0, sizeof(pending));
  pendingCount = 0;  // 每次读取新卡时重置

  bool foundFE = false;
  String parsedData = "";  // 新增：用于保存解析后的数据

  for (byte page = 4; page < pageTotal && !foundFE; page++) {
    byte buffer[18];
    byte size = sizeof(buffer);
    MFRC522::StatusCode status = mfrc522.MIFARE_Read(page, buffer, &size);

    // Serial.print(F("页 "));
    // Serial.print(page);
    // Serial.print(": ");

    if (status == MFRC522::STATUS_OK) {
      dump_byte_array(buffer, 4);  // 输出原始十六进制

      // === 检查当前页是否有 0xFE ===
      byte validLen = 4;
      bool hasFE = false;
      for (byte i = 0; i < 4; i++) {
        if (buffer[i] == 0xFE) {
          validLen = i;  // 只处理0xFE前的数据
          hasFE = true;
          foundFE = true;
          break;
        }
      }

      // === 创建完整缓冲区 (pending + 当前页有效数据) ===
      byte fullBuffer[7];  // pending(最大3) + 当前页(最大4)
      byte fullLen = 0;

      // 复制待处理的字节
      for (byte i = 0; i < pendingCount; i++) {
        fullBuffer[fullLen++] = pending[i];
      }
      // 复制当前页有效字节
      for (byte i = 0; i < validLen; i++) {
        fullBuffer[fullLen++] = buffer[i];
      }

      // === 解析并输出字符 ===
      Serial.print("  |  ");
      byte pos = 0;
      while (pos < fullLen) {
        byte c = fullBuffer[pos];

        // 处理结束符或空字节
        if (c == 0x00) {
          parsedData += '.';
          Serial.print('.');
          pos++;
          continue;
        }

        // ASCII 可打印字符
        if (c >= 0x20 && c <= 0x7E) {
          parsedData += (char)c;
          Serial.write((char)c);
          pos++;
          continue;
        }

        // 处理UTF-8字符（主要处理3字节中文）
        if ((c & 0xE0) == 0xC0) {         // 2字节UTF-8
          if (pos + 1 >= fullLen) break;  // 字节不足，保留
          parsedData += (char)c;
          parsedData += (char)fullBuffer[pos + 1];
          Serial.write(c);
          Serial.write(fullBuffer[pos + 1]);
          pos += 2;
        } else if ((c & 0xF0) == 0xE0) {  // 3字节UTF-8
          if (pos + 2 >= fullLen) break;  // 字节不足，保留

          // 检查后续字节有效性
          if ((fullBuffer[pos + 1] & 0xC0) == 0x80 && (fullBuffer[pos + 2] & 0xC0) == 0x80) {
            parsedData += (char)c;
            parsedData += (char)fullBuffer[pos + 1];
            parsedData += (char)fullBuffer[pos + 2];
            Serial.write(c);
            Serial.write(fullBuffer[pos + 1]);
            Serial.write(fullBuffer[pos + 2]);
            pos += 3;
          } else {
            parsedData += '.';
            Serial.print('.');
            pos++;
          }
        } else {
          parsedData += '.';
          Serial.print('.');
          pos++;
        }
      }

      // === 更新pending ===
      pendingCount = 0;
      if (!hasFE) {
        // 保存未解析的字节供下一页使用
        pendingCount = fullLen - pos;
        for (byte i = 0; i < pendingCount; i++) {
          pending[i] = fullBuffer[pos + i];
        }
      }

      // === 处理结束标志 ===
      if (hasFE) {
        Serial.print("  <<< 找到 0xFE，停止读取!");
      }
      Serial.println();  // 结束本行输出

    } else {
      Serial.print(F("读取失败 ["));
      Serial.print(mfrc522.GetStatusCodeName(status));
      Serial.println("]");
      break;
    }

    if (foundFE) break;  // 发现结束符时终止循环
  }

  // 最终状态报告
  if (foundFE) {
    Serial.println(F("✅ 已检测到 0xFE，停止读取。"));
  } else {
    Serial.println(F("⚠️ 未在页 4 起始的数据中找到 0xFE。"));
  }

  return extractFromEn(parsedData);  // 返回解析后的字符串
}

// 打印字节数组
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

String extractFromEn(String parsedData) {
  int startIndex = parsedData.indexOf("en");  // 查找 "en" 的起始位置

  if (startIndex != -1) {
    // 如果找到 "en"，截取从该位置到末尾的字符串
    return parsedData.substring(startIndex + 2);
  } else {
    // 如果未找到 "en"，返回空字符串或原字符串（根据需求选择）
    return "";  // 或 return parsedData;
  }
}

/**
 * 处理cardData字符串，根据内容执行不同操作
 * @param cardData 输入的卡片数据
 */
void processCardData(String cardData) {
  if (cardData.startsWith("play")) {
    // 提取"play"之后的部分
    String numberPart = cardData.substring(4);  // 使用原始大小写字符串提取数字部分

    // 检查是否有数字部分
    if (numberPart.length() > 0) {
      // 验证剩余部分是否全是数字
      bool allDigits = true;
      for (int i = 0; i < numberPart.length(); i++) {
        if (!isDigit(numberPart[i])) {
          allDigits = false;
          break;
        }
      }

      if (allDigits) {
        int number = numberPart.toInt();
        Serial.print("检测到play指令，提取数字: ");
        Serial.println(number);
        Serial.print("数字类型: int, 值: ");
        Serial.println(number);

        // 在这里你可以使用提取的数字进行其他操作
        myDFPlayer.play(number);
      } else {
        Serial.println("错误: 'play'后面必须跟纯数字");
      }
    } else {
      Serial.println("错误: 'play'后面没有数字");
    }
  } else if (cardData == "stop") {
    Serial.println("收到stop指令");
    // 在这里处理stop指令
    myDFPlayer.stop();
  } else {
    Serial.print("未知指令: ");
    Serial.println(cardData);
  }
}
